package com.ele.server;

import com.ele.client.rpc.ApplicationService;
import com.ele.model.*;
import com.ele.server.dao.*;
import com.ele.server.util.AnswersGenerator;
import com.ele.server.util.AnswersGeneratorImpl;
import com.ele.shared.AuthException;
import com.ele.shared.DataException;
import com.ele.shared.action.*;
import com.ele.shared.dto.grid.SectionGridRow;
import com.ele.shared.dto.grid.WordGridRow;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class ApplicationServiceImpl extends RemoteServiceServlet implements ApplicationService {

    public static final String USER_KEY = "user";
    public static final String SECTION_KEY = "section";

    // Implementation of sample interface method
    public String getMessage(String msg) {
        return "Client said: \"" + msg + "\"<br>Server answered: \"Hi!\"";
    }

    @Override
    public List<SectionGridRow> getLessonGridData() {
        SectionDAO dao = new SectionDAO();
        return dao.getGridData();
    }

    @Override
    public void deleteLessons(Set<Long> ids) {
        SectionDAO dao = new SectionDAO();
        dao.remove(ids);
    }

    @Override
    public void deleteWords(Set<Long> ids) {
        WordDAO dao = new WordDAO();
        dao.remove(ids);
    }

    @Override
    public List<WordGridRow> getWordGridData() {
        WordDAO dao = new WordDAO();
        return dao.getGridData();
    }

    @Override
    public Word getWord(Long id) {
        WordDAO dao = new WordDAO();
        return dao.get(id);
    }

    @Override
    public Word saveWord(Word word) {
        WordDAO dao = new WordDAO();

        if (word.getId() == null) {
            word = dao.insert(word);
        } else {
            word = dao.update(word);
        }

        return word;
    }

    @Override
    public Section getSection(Long id) {
        GenericDAO<Section> dao = new GenericDAO<Section>(Section.class);
        return dao.get(id);
    }

    @Override
    public Section saveSection(Section value) {
        GenericDAO<Section> dao = new GenericDAO<Section>(Section.class);
        if (value.getId() == null) {
            value = dao.insert(value);
        } else {
            value = dao.update(value);
        }

        return dao.get(value.getId());
    }

    @Override
    public void attachWords(Set<Long> ids, Long sectionId) throws DataException {
        Section section = getSection(sectionId);

        WordDAO wordDAO = new WordDAO();
        wordDAO.attachWords(ids, section);
    }

    @Override
    public AppUser login(String email, String password) throws DataException {
        try {
            AppUserDAO dao = new AppUserDAO();
            AppUser appUser = dao.find(email, password);

            getThreadLocalRequest().getSession(true).setAttribute(USER_KEY, appUser);

            return appUser;
        } catch (Exception e) {
            throw new DataException(e.getMessage());
        }
    }

    @Override
    public AppUser getUser() {
        return (AppUser) getThreadLocalRequest().getSession().getAttribute(USER_KEY);
    }

    @Override
    public AppUser signUp(String email, String password) throws DataException {
        AppUser user = new AppUser();
        user.setEmail(email);
        user.setPassword(password);

        try {
            AppUserDAO dao = new AppUserDAO();
            return dao.insert(user);
        } catch (Exception e) {
            throw new DataException(e.getMessage());
        }
    }

    @Override
    public Section getCurrentSection() {
        SectionDAO dao = new SectionDAO();
        Section section = dao.getCurrentSection(getUser().getId());

        if (section != null) {
            QuestionDAO questionDAO = new QuestionDAO();
            Question question = questionDAO.getFirstUncompletedQuestion(section.getId());
            section.setCurrentQuestion(question);
        }

        return section;
    }

    @Override
    public List<Answer> generateAnswer(String questionText) {
        AnswersGenerator generator = new AnswersGeneratorImpl();
        return generator.generate(questionText);
    }

    @Override
    public boolean checkAnswer(String answer, Long questionId) throws AuthException {
        checkUser();

        QuestionDAO dao = new QuestionDAO();
        Question question = dao.get(questionId);

        AppUser user = getUser();
        QuestionUsage usage = dao.getUsage(user.getId(), questionId);
        if (usage == null) {
            usage = new QuestionUsage();
            usage.setUser(user);
            usage.setQuestion(question);
        }

        boolean result = false;

        for (Answer a : question.getAnswers()) {
            if (a.getText().equalsIgnoreCase(answer)) {
                if (usage.getCount() > 0) {
                    usage.decrementCount();
                } else {
                    usage.setCompleted(true);
                }

                result = true;
            }
        }

        if (!result) {
            usage.setCount(3);
        }

        GenericDAO<QuestionUsage> genericDAO = new GenericDAO<QuestionUsage>(QuestionUsage.class);
        if (usage.getId() == null) {
            usage = genericDAO.insert(usage);
        } else {
            usage = genericDAO.update(usage);
        }

        return result;
    }

    @Override
    public List<Action> getActionsList(String answer) throws AuthException {
        checkUser();

        List<Action> result = new ArrayList<Action>();

        if (answer == null) {
            Section section = getCurrentSection();
            result.add(new SetWordsAction(section.getWords()));
            result.add(new SetDescriptionAction(section.getRule()));
            result.add(new LoadImagesAction(section.getCurrentQuestion().getImgUrl()));
            result.add(new SetQuestionAction(section.getCurrentQuestion()));

            getThreadLocalRequest().getSession(true).setAttribute(SECTION_KEY, section);

//            List<Word> words = new ArrayList<Word>();
//            words.add(new Word("table", "стол"));
//            words.add(new Word("wall", "стена"));
//            words.add(new Word("chair", "кресло"));
//            words.add(new Word("face", "лицо"));
//            result.add(new SetWordsAction(words));

//            result.add(new SetDescriptionAction("some description"));

//            result.add(new LoadImagesAction("table"));

//            result.add(new SetQuestionAction(new Question("What's this?", null, null)));
        } else {
            Section section = (Section) getThreadLocalRequest().getSession(true).getAttribute(SECTION_KEY);

            boolean valid = checkAnswer(answer, section.getCurrentQuestion().getId());

            if (valid) {
                result.addAll(getActionsList(null));
                result.add(new SetAnswerSuccessAction());
            } else {
                List<String> answers = new ArrayList<String>();
                for (Answer a : section.getCurrentQuestion().getAnswers()) {
                    answers.add(a.getText());
                }
                result.add(new SetAnswerErrorAction(answers));
            }
        }

        return result;
    }

//    private Section createTestSection(int index) {
//        Section section = new Section();
//        section.setIndex(index);
//        section.setName("Test Section " + index);
//        section.setRule("Test rule for test section " + index);
//
//        List<Question> questions = new ArrayList<Question>();
//        questions.add(createTestQuestion(1));
//        questions.add(createTestQuestion(2));
//        questions.add(createTestQuestion(3));
//        section.setQuestions(questions);
//
//        List<Word> words = new ArrayList<Word>();
//        words.add(createTestWord(1));
//        words.add(createTestWord(2));
//        words.add(createTestWord(3));
//        words.add(createTestWord(4));
//        section.setWords(words);
//
//        return section;
//    }
//
//    private Word createTestWord(int index) {
//        Word word = new Word();
//        word.setText("word #" + index);
//        word.setTranslation("translation #" + index);
//
//        return word;
//    }
//
//    private Question createTestQuestion(int index) {
//        Question question = new Question();
//        question.setText("Test Question " + index);
//
//        List<Answer> answers = new ArrayList<Answer>();
//        answers.add(createTestAnswer(1));
//        question.setAnswers(answers);
//
//        return question;
//    }
//
//    private Answer createTestAnswer(int index) {
//        Answer answer = new Answer();
//        answer.setText("Test Answer " + index);
//
//        return answer;
//    }

    private void checkUser() throws AuthException {
        AppUser user = getUser();
        if (user == null) {
            throw new AuthException();
        }
    }
}